#include <stdlib.h>
#include <stdio.h>
#include <jni.h>
#define ARRAY_LENGTH 6
#ifdef __cplusplus
extern "C"
{
#endif

/*
 *例1 传递字符串，返回字符串
 */
JNIEXPORT jstring JNICALL Java_com_example_myapplicationtest_JniClient_AddStr(JNIEnv *env,jclass arg,jstring a,jstring b) {
	//JNIEnv 也是jni.h中定义的，代表JNI调用的上下文
	//jstring str = (*env)->NewStringUTFChars(env,"Hello JNI");
	//从JNI调用上下文中获取UTF编码的输入文字，将其放在 指针str所指向的一段内存之中
	/*
	 *getStringUTFChar(env,a,0)
	 *重点讲第三个参数：jboolean isCopy:JNI_TRUE,B是原始字符串的一个copy。JNI_FALSE:返回的数据和原来的数据是同一个->注意：当是同一个数据时，不允许改变字符串，否则违反JAVA中字符串不允许改变的原则
	 */	
	const char* str = (*env)->GetStringUTFChars(env,a,0);//用指针指向内存的一个地址，jvm将utf-8编码的字符放进去
	char cap[128] ;
	strcpy(cap,str);
	(*env)->ReleaseStringUTFChars(env,a,str);//使用完str后告诉jvm内存可以释放了
	int i = 0;
	for(i=0;i<strlen(cap);i++){
		//C语言改变数组内存单元的值，需要将内存的值改变
		*(cap+i) = (char)toupper(*(cap+i));
	} 
	return (*env)->NewStringUTF(env,cap);//转换成JNI的jstring类型
 }
/*
 *例子 传递两个int类型参数，返回int类型数据
 */
JNIEXPORT jint JNICALL Java_com_example_myapplicationtest_JniClient_AddInt(JNIEnv *env,jclass clazz,jint a,jint b) {
	return a+b;
}

/*ARRAY_LENGTH
 *例子 传一个int数组返回一个int类型ARRAY_LENGTH
 */
JNIEXPORT jint JNICALL Java_com_example_myapplicationtest_JniClient_intArrayMethod(JNIEnv *env,jclass clazz,jintArray array){
	int i,sum = 0;
	jsize len = (*env)->GetArrayLength(env,array);
	jint *body = (*env)->GetIntArrayElements(env,array,0);
	for(i=0;i<len;i++){
	sum +=body[i];	
	}
	//参数一：原始数据 	参数二：缓冲区数据	活动的形式
	(*env)->ReleaseIntArrayElements(env,array,body,0);
	return sum;
}
/*
 *例子 传递一个boolean类型参数，返回boolean类型
 */
JNIEXPORT jboolean JNICALL Java_com_example_myapplicationtest_JniClient_booleanMethod(JNIEnv *env,jclass clazz,jboolean b){
	return !b;
}
/*
 *例子 无参数，返回一个int[]类型数组
 */
JNIEXPORT jintArray JNICALL Java_com_example_myapplicationtest_JniClient_intMethod(JNIEnv *env,jclass clazz){
	int i = 1;
	jintArray array;//定义的数组对象
	array = (*env)->NewIntArray(env,10);//初始化一个长度为10的jint数组
	for(;i<=10;i++){
		//
		(*env)->SetIntArrayRegion(env,array,i-1,1,&i);		
 	}
	//获取数组元素的个数
	int len = (*env)->GetArrayLength(env,array);
	//获取数组中的首个元素的地址
	jint* elems = (*env)->GetIntArrayElements(env,array,0);
	for(i=0;i<len;i++){
	printf("Element %d is %d",i,elems[i]);
	}
 return array;
}
/*
 *例子 
 *所有的本地方法的第一个参数都是指向JNIEnv的结构
 *虽然仍然是传递数组，但是数组的基类换成了字符串这样一种对象数据类型
 */
JNIEXPORT jobjectArray JNICALL Java_com_example_myapplicationtest_JniClient_stringMethod(JNIEnv *env,jclass obj,jstring string) {
	//通过FindClass()函数在JNI上下文中获取java.lang.String的类型(class),并将其赋予jclass
	jclass objClass = (*env)->FindClass(env,"java/lang/String");
	jobjectArray texts = (*env)->NewObjectArray(env,(jsize)ARRAY_LENGTH,objClass,0);//第四个参数是初始化值 
	jstring jstr;
	char* sa[] = {"Hello","wor","jni","I","hi"};
	for(int i=0;i<ARRAY_LENGTH;i++){
	jstr = (*env)->NewStringUTF(env,sa[i]);
	(*env)->SetObjectArrayElement(env,texts,i,jstr);//必须放入jstring
	}
return texts;
}
/*
 *对象的引用
 *演示的是C程序向java程序传递对象数组
 *而且对象数组中存在不再是字符串，
 *而是一个在java中定义的，含有一个topic属性的MailInfo对象类型
 */
JNIEXPORT jobjectArray JNICALL Java_com_example_myapplicationtest_JniClient_objectMethod(JNIEnv *env,jobject oj,jstring string){
	//这次通过FindClass()函数在JNI上下文中获取的是java.lang.Object的类型Class
	//并将其作为基类开辟出一个长度为5的对象数组，准备用来存放mail
	jclass objclass = (*env)->FindClass(env,"java/lang/object");
	jobjectArray mails = (*env)->NewObjectArray(env,(jsize)ARRAY_LENGTH,objclass,0);
	jclass objectClass = (*env)->FindClass(env,"MailInfo");
	//创建一个jfieldID类型的变量，在JNI 中，操作对象属性是通过jfieldID进行的
	jfieldID topicFieldId = (*env)->GetFieldID(env,objectClass,"topic","Ljava/lang/String;");
	int i = 0;
	for(;i<ARRAY_LENGTH;i++){
		(*env)->SetObjectField(env,oj,topicFieldId,string);

		(*env)->SetObjectArrayElement(env, mails, i, oj);
	}
	return mails;
}
#ifdef __cplusplus
}
#endif

